//
// Created by Lai on 2021/6/3.
//

#include <logUtil.h>
#include "comm_gl.hpp"

TextVertex::TextVertex() : ebo(0), vertexVbo(0), uvVbo(0), childId(-1), vao(0) {
    glGenVertexArrays(1, &vao);
}

TextVertex::~TextVertex() {
    if (ebo != 0) {
        glDeleteBuffers(1, &ebo);
        ebo = 0;
    }

    if (uvVbo != 0) {
        glDeleteBuffers(1, &uvVbo);
        uvVbo = 0;
    }

    if (vertexVbo != 0) {
        glDeleteBuffers(1, &vertexVbo);
        vertexVbo = 0;
    }
    if (vao != 0) {
        glDeleteVertexArrays(1, &vao);
        vao = 0;
    }

    LOGCATE("~TextVertex()")
}

int TextVertex::InitVertexVbo2D(float *data, int vertexCount, GLuint layout) {
    BindVAO();
    glGenBuffers(1, &vertexVbo);
    glBindBuffer(GL_ARRAY_BUFFER, vertexVbo);
    glBufferData(GL_ARRAY_BUFFER, vertexCount * 2 * sizeof(float), data, GL_DYNAMIC_DRAW);
    glVertexAttribPointer(layout, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void *) 0);
    glEnableVertexAttribArray(layout);
    UnBindVAO();
    return 0;
}


void TextVertex::BindVertex(GLuint vertexLayout, GLuint uvLayout) {
    BindVAO();

    //顶点数据
    glGenBuffers(1, &vertexVbo);
    glBindBuffer(GL_ARRAY_BUFFER, vertexVbo);
    glBufferData(GL_ARRAY_BUFFER, 0, nullptr, GL_DYNAMIC_DRAW);
    glVertexAttribPointer(vertexLayout, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void *) 0);
    glEnableVertexAttribArray(vertexLayout);

    //uv数据
    glGenBuffers(1, &uvVbo);
    glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
    glBufferData(GL_ARRAY_BUFFER, 0, nullptr, GL_DYNAMIC_DRAW);
    glVertexAttribPointer(uvLayout, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void *) 0);
    glEnableVertexAttribArray(uvLayout);

    //Ebo
    glGenBuffers(1, &ebo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 0, nullptr,
                 GL_DYNAMIC_DRAW);
    UnBindVAO();
}


int TextVertex::InitUvVbo2D(float *data, int vertexCount, GLuint layout) {
    BindVAO();
    glGenBuffers(1, &uvVbo);
    glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
    glBufferData(GL_ARRAY_BUFFER, vertexCount * 2 * sizeof(float), data, GL_DYNAMIC_DRAW);
    glVertexAttribPointer(layout, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void *) 0);
    glEnableVertexAttribArray(layout);
    return 0;
}

void TextVertex::UpdateVertexVbo2D(float *data, int vertexCount) {
    if (vertexVbo != 0) {
        glBindBuffer(GL_ARRAY_BUFFER, vertexVbo);
        glBufferData(GL_ARRAY_BUFFER, vertexCount * 2 * sizeof(float), data, GL_DYNAMIC_DRAW);
    }
}


void TextVertex::UpdateUvVbo2D(float *data, int vertexCount) {
    if (uvVbo != 0) {
        glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
        glBufferData(GL_ARRAY_BUFFER, vertexCount * 2 * sizeof(float), data, GL_DYNAMIC_DRAW);
    }
}


void TextVertex::updateIndex(unsigned int *indexData, int indexCount) {
    if (ebo != 0) {
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * sizeof(unsigned int), indexData,
                     GL_DYNAMIC_DRAW);
    }
}

void TextVertex::BindVAO() const {
    glBindVertexArray(vao);
}

void TextVertex::UnBindVAO() {
    glBindVertexArray(0);
}

int TextVertex::InitEbo(unsigned int *indexData, int indexCount) {
    BindVAO();
    glGenBuffers(1, &ebo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * sizeof(unsigned int), indexData,
                 GL_DYNAMIC_DRAW);
    UnBindVAO();
    return 0;
}


TextGroup::~TextGroup() {
    for (auto *text:allTextVertex) {
        delete text;
    }
    allTextVertex.clear();

    LOGCATE("~TextGroup")
}

TextGroup::TextGroup() : allTextVertex() {

}


void TextGroup::UpdateVertexVbo2D(int childId, float *data, int vertexCount) {

    TextVertex *vertex = nullptr;
    int i = FindTextVertex(childId, vertex);

    if (i == 0 && vertex != nullptr) {
        vertex->UpdateVertexVbo2D(data, vertexCount);
    }
}


int TextGroup::FindTextVertex(int childId, TextVertex *&pVao) {
    for (auto &pt:allTextVertex) {
        if (pt->childId == childId) {
            pVao = pt;
            return 0;
        }
    }

    return -1;
}

void TextGroup::UpdateUvVbo2D(int childId, float *data, int vertexCount) {
    TextVertex *vertex = nullptr;
    int i = FindTextVertex(childId, vertex);

    if (i == 0 && vertex != nullptr) {
        vertex->UpdateUvVbo2D(data, vertexCount);
    }
}


int TextGroup::updateIndex(int childId, unsigned int *indexData, int indexCount) {
    TextVertex *vertex = nullptr;
    int i = FindTextVertex(childId, vertex);

    if (i == 0 && vertex != nullptr) {
        vertex->updateIndex(indexData, indexCount);
    }

    return 0;
}

void TextGroup::ClearVbo(int childId) {
    TextVertex *vertex = nullptr;
    int i = FindTextVertex(childId, vertex);

    if (i == 0 && vertex != nullptr) {
        vertex->updateIndex(nullptr, 0);
        vertex->UpdateUvVbo2D(nullptr, 0);
        vertex->UpdateVertexVbo2D(nullptr, 0);
    }
}

void TextGroup::CreateVertex(int childId) {
    TextVertex *vertex = nullptr;
    int i = FindTextVertex(childId, vertex);
    if (i != 0) {
        TextVertex *textVertex = new TextVertex();
        textVertex->childId = childId;
        allTextVertex.push_back(textVertex);
    }
}

void TextGroup::BindVao(int childId) {
    TextVertex *vertex = nullptr;
    int i = FindTextVertex(childId, vertex);
    if (i == 0) {
        vertex->BindVAO();
    }
}

void TextGroup::UnBindVao(int chi) {
    TextVertex *vertex = nullptr;
    int i = FindTextVertex(chi, vertex);
    if (i == 0) {
        vertex->UnBindVAO();
    }
}

int TextGroup::BindVertex(int childId, GLuint vertexLayout, GLuint uvLayout) {
    TextVertex *vertex = nullptr;
    int i = FindTextVertex(childId, vertex);
    if (i == 0) {
        vertex->BindVertex(vertexLayout, uvLayout);
    }
    return i;
}


VaoGroupManager::VaoGroupManager() : vaoGroupMap() {

}

VaoGroupManager::~VaoGroupManager() {
    for (auto &vao : vaoGroupMap) {
        delete vao.second;
        vao.second = nullptr;
    }
    vaoGroupMap.clear();
}

int VaoGroupManager::CreateTextGroup(int id, TextGroup **vaoGroup) {
    *vaoGroup = new TextGroup();

    std::pair<int, TextGroup *> stl = {id, *vaoGroup};

    vaoGroupMap.insert(stl);

    return 0;
}


int VaoGroupManager::FindGroup(int id, TextGroup *&pVaoGroup) {
    const std::map<int, TextGroup *>::iterator &iterator = vaoGroupMap.find(id);

    if (iterator != vaoGroupMap.end()) {
        pVaoGroup = iterator->second;
        return 0;
    }

    return -1;
}


int VaoGroupManager::RemoveId(int id) {
    const std::map<int, TextGroup *>::iterator &iterator = vaoGroupMap.find(id);

    if (iterator != vaoGroupMap.end()) {
        delete iterator->second;
        iterator->second = nullptr;
        vaoGroupMap.erase(iterator);
        return 0;
    }

    return -1;
}


void VaoGroupManager::PrintAll() {
    for (auto &map : vaoGroupMap) {
        LOGCATE("--- vaoMap layerId %d--- --- ", map.first)
        for (auto &text : map.second->allTextVertex) {
            LOGCATE("vao %d childId %d vertexVbo  %d  uvVbo %d ebo %d", text->vao, text->childId,
                    text->vertexVbo,
                    text->uvVbo, text->ebo)
        }
        LOGCATE("--- --- --- --- --- --- --- ");
    }
}




